package com.ipan.poi.excel.log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.text.MessageFormat;
import java.util.Date;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ipan.kits.io.FileUtil;
import com.ipan.kits.time.DateFormatUtil;

/**
 * 文件记录工具基类，支持多线程并发；
 * 支持直接写入文件（如果写入频率比较高，频繁读写文件性能会比较低）；
 * 支持先保存到内存，然后再刷新到文件（推荐）；
 * 
 * @author iPan
 * @version 2013-04-02
 */
public abstract class PoiAppFileLogger {
	// 状态
	public static final String MSG_SUCCESS = "成功";
	public static final String MSG_FAIL = "失败";
	public static final String EOL = System.getProperty("line.separator");
	public static final String MSG_HR = "-------------------------------------------------------------" + EOL;
	public static final String DEFAULT_DATE_PATTERN = "yyyy/MM/dd HH:mm:ss";
	
	protected ThreadLocal<StringBuilder> cache = new ThreadLocal<StringBuilder>() {
        protected synchronized StringBuilder initialValue() {
            return new StringBuilder();
        }};

    protected int fileSize = 3 * 1024 * 1024; // 默认一个文件写3M左右
        
    protected String filePath = null;
    
    protected Logger logger = LoggerFactory.getLogger(getClass());
    
    public PoiAppFileLogger(String filePath) {
    	this.filePath = filePath;
    }
    
    public int getFileSize() {
		return fileSize;
	}

	public void setFileSize(int fileSize) {
		this.fileSize = fileSize;
	}

	public void appendToCache(String pattern, Object ... args) {
		String text = this.getText(pattern, args);
		this.getCache().append(text);
	}
	
	public void appendToCache(String text) {
		if (text == null) {
			return ;
		}
		this.getCache().append(text);
	}
	
	public void appendToCache(String[] args) {
		if (args == null || args.length < 1) {
			return ;
		}
		StringBuilder buf = this.getCache();
		for (String s : args) {
			buf.append(s);
		}
	}
	
	public void flush() {
		write(this.getCache().toString());
		cleanCache();
	}
	
	private synchronized void checkFileSize() { // 增加文件大小超限后自动滚动 2021-12-08
		File file = new File(filePath);
		if (file.exists() && file.length() >= fileSize) {
			String fileName = FileUtil.getFileName(filePath);
			String dateStr = DateFormatUtil.formatDate("yyyyMMddHHmmss", new Date());
			int extIndex = fileName.lastIndexOf(".");
			String newFileName = fileName.substring(0, extIndex) + "_" + dateStr + fileName.substring(extIndex);
			String newFilePath = filePath.replace(fileName, newFileName);
			File fileTo = new File(newFilePath);
			FileOutputStream fout = null;
			try {
				FileUtil.copy(file, fileTo);
				fout = new FileOutputStream(file, false);
				fout.write("".getBytes());
			} catch(Exception e) {
				logger.error("文件大小超标后处理失败", e);
			} finally {
				if (fout != null) {
					try {
						fout.close();
					} catch (IOException e) {
					}
				}
			}
		}
	}
	
	public synchronized void write(String pattern, Object ... args) {
		String text = this.getText(pattern, args);
		write(text);
	}
	
	public synchronized void write(String str) {
		PrintStream print = null; 
		try {
			print = getPrintStream();
			print.print(str);
		} catch (Exception e) {
			throw new RuntimeException("写入文件[" + filePath + "]失败！", e);
		} finally {
			if (print != null) {
				print.close();
			}
		}
		
		checkFileSize();
	}
	
	public String getText(String pattern, Object ... args) {
		return MessageFormat.format(pattern, args) + EOL;
	}
	
	public String getDefaultDateStr() {
		return getDateStr(DEFAULT_DATE_PATTERN);
	}
	
	public String getDateStr(String pattern) {
		return DateFormatUtils.format(new Date(), pattern);
	}
	
	public StringBuilder getCache() {
		return this.cache.get();
	}
	
	public void cleanCache() {
		this.cache.remove();
	}
	
	public String getFilePath() {
		return filePath;
	}

	private PrintStream getPrintStream() throws UnsupportedEncodingException, FileNotFoundException {
		File file = new File(filePath);
		if (!file.exists()) {
			FileUtil.createFile(file.getAbsolutePath());
		}
		return new PrintStream(new FileOutputStream(file, true), true, "UTF-8");
	}
}
